package state

import (
	//"fmt"
	"osiris/config"
	"osiris/core/conversion"
	"osiris/core/routine"
	"osiris/dto"
	"osiris/logger"
	"osiris/ocrypto/ecdsa"
)

// ReleaseTxHandler 代币解押交易
type ReleaseTxHandler struct {
	TxData dto.TxData
}

func (txHandler ReleaseTxHandler) Verify(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Warn(map[string]interface{}{"[state] [Verify Release TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Warn(map[string]interface{}{"[state] [Verify Release TX]": "unknown peer trie!"})
		return false
	}

	//检查来源节点是否存在
	peerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.FromAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Verify Release Tx] core.StrToPeerIDByte()": err})
		return false
	}
	fromLeaf, fromExist := tempPeerTrie.GetLeaf(peerIDBytes)
	if !fromExist {
		logger.Warn(map[string]interface{}{"[state] [Verify Release TX]": "source peer does not exist!"})
		return false
	}

	//检查来源节点的余额是否足够
	if fromLeaf.Asset < txHandler.TxData.Amount {
		logger.Warn(map[string]interface{}{"[state] [Verify Release TX]": "source peer does not have enough asset!"})
		return false
	}

	//检查目的账户是否存在
	toAccountBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toExist := tempAccountTrie.HasLeaf(toAccountBytes)
	if !toExist {
		logger.Warn(map[string]interface{}{"[state] [Verify Release TX]": "destination account does not exist!"})
		return false
	}

	return true
}

func (txHandler ReleaseTxHandler) Commit(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Error(map[string]interface{}{"[state] [Verify Release TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Error(map[string]interface{}{"[state] [Verify Release TX]": "unknown peer trie!"})
		return false
	}

	//修改来源节点状态
	peerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.FromAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Commit Release Tx] core.StrToPeerIDByte()": err})
		return false
	}
	fromLeaf, fromExist := tempPeerTrie.GetLeaf(peerIDBytes)
	if !fromExist {
		logger.Error(map[string]interface{}{"[state] [Commit Release TX]": "source peer does not exist!"})
		return false
	}
	fromLeaf.CommitAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)

	//修改目的账户状态：加金额
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Commit Release TX]": "destination account addr does not exist!"})
		return false
	}
	toLeaf.CommitAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	//logger.Debug(map[string]interface{}{"[state] [Commit Transform TX]": fmt.Sprintf("hash: %s,  fromAddr: %s,  amount: %d, current: %d", txHandler.TxData.TxHash, txHandler.TxData.FromAddr, txHandler.TxData.Amount, fromLeaf.Asset)})

	//如果nonce达到了配置里的最大nonce值，从0开始（为了区别账户创建时的最小随机数1），否则+1
	if toLeaf.Nonce == config.MaxAccountNonce.Int64() {
		toLeaf.Nonce = 0
	} else {
		toLeaf.Nonce += 1
	}

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  toAccountAddrBytes,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Add(&PeerCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  peerIDBytes,
			Leaf: fromLeaf,
		}},
		Trie: tempPeerTrie,
	}).Execute()
}

func (txHandler ReleaseTxHandler) Undo(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Error(map[string]interface{}{"[state] [Undo Release TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Error(map[string]interface{}{"[state] [Undo Release TX]": "unknown peer trie!"})
		return false
	}

	//修改来源节点状态
	fromPeerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.FromAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Undo Release Tx] core.StrToPeerIDByte()": err})
		return false
	}
	fromLeaf, fromExist := tempPeerTrie.GetLeaf(fromPeerIDBytes)
	if !fromExist {
		logger.Error(map[string]interface{}{"[state] [Undo Release TX]": "source peer does not exist"})
		return false
	}
	fromLeaf.UndoAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)

	//修改目的账户状态
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Undo Release TX]": "destination account does not exist "})
		return false
	}
	toLeaf.UndoAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	if toLeaf.Nonce == 0 {
		toLeaf.Nonce = config.MaxAccountNonce.Int64()
	} else {
		toLeaf.Nonce -= 1
	}

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  toAccountAddrBytes,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Add(&PeerCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  fromPeerIDBytes,
			Leaf: fromLeaf,
		}},
		Trie: tempPeerTrie,
	}).Execute()
}
